 /***************************************************************************************************
  * Copyright (c) 2005, 2006 IBM Corporation and others. All rights reserved. This program and the
  * accompanying materials are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors: IBM Corporation - initial API and implementation
  **************************************************************************************************/
 package org.eclipse.ui.internal.intro.impl.presentations;

 import java.util.Map ;

 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IMenuListener;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.util.Geometry;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.PaintEvent;
 import org.eclipse.swt.events.PaintListener;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Layout;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.ui.IWorkbenchPreferenceConstants;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.RectangleAnimation;
 import org.eclipse.ui.internal.WorkbenchMessages;
 import org.eclipse.ui.internal.WorkbenchWindow;
 import org.eclipse.ui.internal.dnd.DragUtil;
 import org.eclipse.ui.internal.intro.impl.IntroPlugin;
 import org.eclipse.ui.internal.intro.impl.Messages;
 import org.eclipse.ui.internal.intro.impl.model.IntroLaunchBarElement;
 import org.eclipse.ui.internal.intro.impl.model.IntroLaunchBarShortcut;
 import org.eclipse.ui.internal.intro.impl.model.IntroTheme;
 import org.eclipse.ui.internal.intro.impl.swt.SharedStyleManager;
 import org.eclipse.ui.internal.intro.impl.util.ImageUtil;
 import org.eclipse.ui.internal.layout.ITrimManager;
 import org.eclipse.ui.internal.layout.IWindowTrim;
 import org.eclipse.ui.intro.IIntroPart;
 import org.eclipse.ui.intro.config.CustomizableIntroPart;
 import org.eclipse.ui.intro.config.IIntroURL;
 import org.eclipse.ui.intro.config.IntroURLFactory;

 /**
  * This class is responsible for creating the intro launch bar in the provided parent. It creates
  * 'restore' and 'close' actions, as well as actions for each shortcut element contributed in the
  * extension point.
  *
  * @since 3.1
  */
 public class IntroLaunchBar implements IWindowTrim {

     private Composite container;

     protected ToolBarManager toolBarManager;

     protected int orientation;

     protected int location;

     protected String lastPageId;

     protected Action closeAction = null;

     private IntroLaunchBarElement element;

     protected boolean simple;

     private String presentationId;
     
     private IntroTheme theme;

     static final int[] TOP_LEFT_CORNER = new int[] { 0, 6, 1, 5, 1, 4, 4, 1, 5, 1, 6, 0 };

     static final int[] TOP_RIGHT_CORNER = new int[] { -6, 0, -5, 1, -4, 1, -1, 4, -1, 5, 0, 6 };

     static final int[] BOTTOM_LEFT_CORNER = new int[] { 0, -6, 1, -5, 1, -4, 4, -1, 5, -1, 6, 0 };

     static final int[] BOTTOM_RIGHT_CORNER = new int[] { -6, 0, -5, -1, -4, -1, -1, -4, -1, -5, 0, -6 };

     static final int[] SIMPLE_TOP_LEFT_CORNER = new int[] { 0, 2, 1, 1, 2, 0 };

     static final int[] SIMPLE_TOP_RIGHT_CORNER = new int[] { -2, 0, -1, 1, 0, 2 };

     static final int[] SIMPLE_BOTTOM_LEFT_CORNER = new int[] { 0, -2, 1, -1, 2, 0 };

     static final int[] SIMPLE_BOTTOM_RIGHT_CORNER = new int[] { -2, 0, -1, -1, 0, -2 };

     static final String S_STORED_LOCATION = "introLaunchBar.location"; //$NON-NLS-1$

     private final static String LAUNCH_COMMAND_BASE = "http://org.eclipse.ui.intro/showPage?id="; //$NON-NLS-1$

     private Color fg;

     private Color bg;

     class BarLayout extends Layout {

         protected Point computeSize(Composite composite, int wHint, int hHint, boolean changed) {
             boolean vertical = (orientation & SWT.VERTICAL) != 0;
             int marginWidth = vertical | isPlain() ? 1 : simple ? 3 : 7;
             int marginHeight = !vertical | isPlain() ? 1 : simple ? 3 : 7;
             int width = 0;
             int height = 0;

             Point tsize = toolBarManager.getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT, changed);

             if (vertical) {
                 width = tsize.x;
                 height = tsize.y;
             } else {
                 height = tsize.y;
                 width = tsize.x;
             }
             if (vertical) {
                 width += marginWidth;
                 height += marginHeight + marginHeight;
             } else {
                 width += marginWidth + marginWidth;
                 height += marginHeight;
             }
             return new Point(width, height);
         }

         protected void layout(Composite composite, boolean changed) {
             boolean vertical = (orientation & SWT.VERTICAL) != 0;
             int marginWidth = vertical | isPlain() ? 1 : simple ? 4 : 7;
             int marginHeight = !vertical | isPlain() ? 1 : simple ? 4 : 7;

             Point tsize = toolBarManager.getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT, changed);
             Rectangle carea = composite.getClientArea();
             int x = carea.x + (location == SWT.LEFT ? 0 : marginWidth);
             int y = carea.y + marginHeight;

             if (vertical) {
                 toolBarManager.getControl().setBounds(x, y, carea.width - marginWidth, tsize.y);
             } else {
                 toolBarManager.getControl().setBounds(x, y, tsize.x, carea.height - marginHeight);
             }
         }
     }

     public IntroLaunchBar(int orientation, String lastPageId, IntroLaunchBarElement element, IntroTheme theme) {
         this.orientation = orientation;
         this.location = element.getLocation();
         this.lastPageId = lastPageId;
         this.element = element;
         this.theme = theme;

         simple = true;
         presentationId = PlatformUI.getPreferenceStore().getString(
                 IWorkbenchPreferenceConstants.PRESENTATION_FACTORY_ID);
         loadStoredLocation();
     }

     private void loadStoredLocation() {
         IDialogSettings settings = IntroPlugin.getDefault().getDialogSettings();
         try {
             int storedLocation = settings.getInt(S_STORED_LOCATION);
             if (storedLocation > 0)
                 setLocation(storedLocation);
         } catch (NumberFormatException e) {
             // The stored value either does not exist or
 // is corrupted - just pick the default silently.
 }
     }

     private void storeLocation() {
         IDialogSettings settings = IntroPlugin.getDefault().getDialogSettings();
         settings.put(S_STORED_LOCATION, this.location);
     }

     /**
      * This method now calls dock(location) and then adds itself to the window trim. This is to
      * support the re-ordering of IWindowTrim lifecycle related to dock().
      */
     public void createInActiveWindow() {
         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();

         dock(location);

         ITrimManager trimManager = getTrimManager();
         trimManager.addTrim(location, this);
         window.getShell().layout();
     }

     /**
      * Get the trim manager from the default workbench window. If the current
      * workbench window is -not- the <code>WorkbenchWindow</code> then return null.
      *
      * @return The trim manager for the current workbench window
      */
     private ITrimManager getTrimManager() {
         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
         if (window instanceof WorkbenchWindow)
             return ((WorkbenchWindow)window).getTrimManager();
         
         return null; // not using the default workbench window
 }
     
     protected boolean isPlain() {
         return !"org.eclipse.ui.presentations.default".equals(presentationId); //$NON-NLS-1$
 }

     public void createControl(Composite parent) {
         container = new Composite(parent, SWT.NULL);
         computeColors(parent.getDisplay());
         container.setLayout(new BarLayout());
         // boolean vertical = (orientation & SWT.VERTICAL) != 0;
 toolBarManager = new ToolBarManager(SWT.FLAT | orientation);


         fillToolBar();
         // coolBar = new CoolBar(container, SWT.NULL);
 // CoolItem coolItem = new CoolItem(coolBar, SWT.NULL);
 // toolBarManager.createControl(coolBar);
 toolBarManager.createControl(container);
         ToolBar toolBar = toolBarManager.getControl();

         // coolItem.setControl(toolBar);
 // Point toolBarSize = toolBar.computeSize(SWT.DEFAULT,
 // SWT.DEFAULT);
 // Set the preffered size to the size of the toolbar plus trim
 // Point preferredSize = coolItem.computeSize(toolBarSize.x,
 // toolBarSize.y);
 // coolItem.setPreferredSize(preferredSize);

         if (bg != null) {
             toolBar.setBackground(bg);
             // coolBar.setBackground(bg);
 }
         container.addPaintListener(new PaintListener() {

             public void paintControl(PaintEvent e) {
                 onPaint(e);
             }
         });
         MenuManager manager = new MenuManager();
         IMenuListener listener = new IMenuListener() {

             public void menuAboutToShow(IMenuManager manager) {
                 contextMenuAboutToShow(manager);
             }
         };
         manager.setRemoveAllWhenShown(true);
         manager.addMenuListener(listener);
         Menu contextMenu = manager.createContextMenu(toolBarManager.getControl());
         toolBarManager.getControl().setMenu(contextMenu);
         IntroPlugin.getDefault().setLaunchBar(this);
     }

     protected void startDragging(Point position, boolean usingKeyboard) {
         Rectangle dragRect = DragUtil.getDisplayBounds(getControl());
         startDrag(this, dragRect, position, usingKeyboard);
     }

     private void startDrag(Object toDrag, Rectangle dragRect, Point position, boolean usingKeyboard) {

         DragUtil.performDrag(toDrag, dragRect, position, !usingKeyboard);
     }

     protected void onPaint(PaintEvent e) {
         GC gc = e.gc;
         Color color = fg;
         if (color == null) {
             color = e.display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
         }
         gc.setForeground(color);
         if (bg != null)
             gc.setBackground(bg);
         if (isPlain()) {
             Point size = container.getSize();
             gc.fillRectangle(0, 0, size.x, size.y);
             gc.drawRectangle(0, 0, size.x - 1, size.y - 1);
         } else {
             switch (location) {
             case SWT.LEFT:
                 paintLeft(gc);
                 break;
             case SWT.RIGHT:
                 paintRight(gc);
                 break;
             case SWT.BOTTOM:
                 paintBottom(gc);
                 break;
             }
         }
     }

     private void paintLeft(GC gc) {
         int[] top = simple ? SIMPLE_TOP_RIGHT_CORNER : TOP_RIGHT_CORNER;
         int[] bot = simple ? SIMPLE_BOTTOM_RIGHT_CORNER : BOTTOM_RIGHT_CORNER;
         int[] shape = new int[top.length + bot.length + 4];
         int index = 0;
         Point size = container.getSize();
         int x = size.x - 1;
         int y = 0;
         index = fillShape(shape, top, index, x, y, false);
         y = size.y - 1;
         index = fillShape(shape, bot, index, x, y, true);
         shape[index++] = -1;
         shape[index++] = size.y - 1;
         shape[index++] = -1;
         shape[index++] = 0;
         gc.fillPolygon(shape);
         gc.drawPolygon(shape);
     }

     private void paintBottom(GC gc) {
         int[] left = simple ? SIMPLE_TOP_LEFT_CORNER : TOP_LEFT_CORNER;
         int[] right = simple ? SIMPLE_TOP_RIGHT_CORNER : TOP_RIGHT_CORNER;
         int[] shape = new int[left.length + right.length + 4];
         int index = 0;
         Point size = container.getSize();
         int x = 0;
         int y = 0;
         index = fillShape(shape, left, index, x, y, false);
         x = size.x - 1;
         index = fillShape(shape, right, index, x, y, false);
         shape[index++] = size.x - 1;
         shape[index++] = size.y;
         shape[index++] = 0;
         shape[index++] = size.y;
         gc.fillPolygon(shape);
         gc.drawPolygon(shape);
     }

     private void paintRight(GC gc) {
         int[] top = simple ? SIMPLE_TOP_LEFT_CORNER : TOP_LEFT_CORNER;
         int[] bot = simple ? SIMPLE_BOTTOM_LEFT_CORNER : BOTTOM_LEFT_CORNER;
         int[] shape = new int[top.length + bot.length + 4];
         int index = 0;
         Point size = container.getSize();
         int x = 0;
         int y = 0;
         index = fillShape(shape, top, index, x, y, false);
         shape[index++] = size.x;
         shape[index++] = 0;
         shape[index++] = size.x;
         shape[index++] = size.y - 1;
         x = 0;
         y = size.y - 1;
         fillShape(shape, bot, index, x, y, true);
         gc.fillPolygon(shape);
         gc.drawPolygon(shape);
     }


     private int fillShape(int[] shape, int[] points, int index, int x, int y, boolean reverse) {
         int fill = points.length;
         for (int i = 0; i < points.length / 2; i++) {
             if (!reverse) {
                 shape[index++] = x + points[2 * i];
                 shape[index++] = y + points[2 * i + 1];
             } else {
                 shape[index + fill - 2 - 2 * i] = x + points[2 * i];
                 shape[index + fill - 1 - 2 * i] = y + points[2 * i + 1];
             }
         }
         if (reverse) {
             index += fill;
         }
         return index;
     }

     private void computeColors(Display display) {
         if (element.getBackground() != null) {
             String value = resolveColor(element.getBackground());
             if (value!=null) {
                 RGB r = SharedStyleManager.parseRGB(value);
                 if (r != null)
                     bg = new Color(display, r);
             }
         }
         if (element.getForeground() != null) {
             String value = resolveColor(element.getForeground());
             if (value!=null) {
                 RGB r = SharedStyleManager.parseRGB(value);
                 if (r != null)
                     fg = new Color(display, r);
             }
         }
     }
     
     private String resolveColor(String value) {
         if (value.indexOf('$')== -1)
             return value;
         if (value.charAt(0)=='$' && value.charAt(value.length()-1)=='$' && theme!=null) {
             Map properties = theme.getProperties();
             if (properties!=null) {
                 String key = value.substring(1, value.length()-1);
                 return (String )properties.get(key);
             }
         }
         return value;
     }

     public Control getControl() {
         return container;
     }

     public void dispose() {
         if (container != null) {
             container.dispose();
         }
         if (toolBarManager != null) {
             toolBarManager.dispose();
             toolBarManager.removeAll();
         }

         toolBarManager = null;
         container = null;

         if (bg != null)
             bg.dispose();
         if (fg != null)
             fg.dispose();
     }

     private void fillToolBar() {
         Action action;

         closeAction = new Action("close") { //$NON-NLS-1$

             public void run() {
                 closeLaunchBar(false);
             }
         };
         closeAction.setText(Messages.IntroLaunchBar_close_label);
         closeAction.setToolTipText(Messages.IntroLaunchBar_close_tooltip);
         /*
          * closeAction.setImageDescriptor(ImageUtil
          * .createImageDescriptor("full/elcl16/close_view.gif")); //$NON-NLS-1$
          */

         action = new Action("restore") { //$NON-NLS-1$

             public void run() {
                 openPage(lastPageId);
             }
         };
         action.setToolTipText(Messages.IntroLaunchBar_restore_tooltip);
         action.setImageDescriptor(ImageUtil.createImageDescriptor("full/etool16/restore_welcome.gif")); //$NON-NLS-1$
 // toolBarManager.add(closeAction);
 toolBarManager.add(action);
         toolBarManager.add(new Separator());
         if (element == null)
             return;
         IntroLaunchBarShortcut[] shortcuts = element.getShortcuts();
         for (int i = 0; i < shortcuts.length; i++) {
             IntroLaunchBarShortcut shortcut = shortcuts[i];
             addShortcut(shortcut, toolBarManager);
         }
     }

     private void addShortcut(final IntroLaunchBarShortcut shortcut, IToolBarManager toolBarManager) {
         Action action = new Action(shortcut.getToolTip()) {

             public void run() {
                 executeShortcut(shortcut.getURL());
             }
         };
         action.setImageDescriptor(shortcut.getImageDescriptor());
         action.setToolTipText(shortcut.getToolTip());
         toolBarManager.add(action);
     }

     public void close() {
         closeLaunchBar(false);
     }

     protected IIntroPart closeLaunchBar(boolean restore) {

         IntroPlugin.getDefault().setLaunchBar(null);
         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();

         // if we've already been removed, this won't hurt us
 getTrimManager().removeTrim(this);

         IIntroPart intro = null;
         if (restore) {
             intro = PlatformUI.getWorkbench().getIntroManager().showIntro(window, false);
             CustomizableIntroPart cpart = (CustomizableIntroPart) intro;
             Rectangle startBounds = Geometry.toDisplay(getControl().getParent(), getControl().getBounds());
             Rectangle endBounds = Geometry.toDisplay(cpart.getControl().getParent(), cpart.getControl()
                     .getBounds());

             RectangleAnimation animation = new RectangleAnimation(window.getShell(), startBounds, endBounds);
             animation.schedule();
         }
         dispose();
         window.getShell().layout();
         return intro;
     }

     protected void executeShortcut(String url) {
         IIntroURL introURL = IntroURLFactory.createIntroURL(url);
         if (introURL != null) {
             IIntroPart intro = closeLaunchBar(true);
             if (intro == null)
                 return;
             introURL.execute();
         }
     }

     protected void openPage(String id) {
         IIntroPart intro = closeLaunchBar(true);
         if (intro == null)
             return;
         StringBuffer url = new StringBuffer ();
         url.append(LAUNCH_COMMAND_BASE);
         url.append(id);
         IIntroURL introURL = IntroURLFactory.createIntroURL(url.toString());
         if (introURL != null)
             introURL.execute();
     }

     protected void contextMenuAboutToShow(IMenuManager manager) {
         manager.add(closeAction);
     }

     public void dock(int side) {
         dispose();
         setLocation(side);
         storeLocation();
         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
         createControl(window.getShell());
     }

     private void setLocation(int location) {
         this.orientation = (location == SWT.LEFT || location == SWT.RIGHT) ? SWT.VERTICAL : SWT.HORIZONTAL;
         this.location = location;
     }

     public int getValidSides() {
         return SWT.LEFT | SWT.RIGHT | SWT.BOTTOM;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.IWindowTrim#getId()
      */
     public String getId() {
         return "org.eclipse.ui.internal.intro.impl.presentations.IntroLaunchBar"; //$NON-NLS-1$
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.IWindowTrim#getDisplayName()
      */
     public String getDisplayName() {
         return WorkbenchMessages.TrimCommon_IntroBar_TrimName;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.IWindowTrim#isCloseable()
      */
     public boolean isCloseable() {
         return element.getClose();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.IWindowTrim#handleClose()
      */
     public void handleClose() {
         closeLaunchBar(false);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IWindowTrim#getWidthHint()
      */
     public int getWidthHint() {
         return SWT.DEFAULT;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IWindowTrim#getHeightHint()
      */
     public int getHeightHint() {
         return SWT.DEFAULT;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IWindowTrim#isResizeable()
      */
     public boolean isResizeable() {
         return false;
     }

 }

